import sys
import os
import time

import pyautogui
import pygetwindow as gw
import cv2
import mss
import numpy as np
import win32gui

from PIL import Image


def resource_path(relative_path):
    """
    加载图片
    :param relative_path:
    :return:
    # 示例：加载图片
    # image_path = resource_path("images/icon.jpg")
    # print("图片路径", image_path)
    # image_path = resource_path("images/login/kuai_su_deng_lu.png")
    # print("图片路径2", image_path)
    """
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


def get_window_size(hwnd):
    """
    获取窗口大小、以及屏幕的x、y轴的位置（从左上角算起）

    :param hwnd: 窗口句柄
    :return: width, height, left, top
    """
    # 获取窗口的外框矩形（包括标题栏和边框）
    rect = win32gui.GetWindowRect(hwnd)
    left, top, right, bottom = rect

    # 计算宽度和高度
    width = right - left
    height = bottom - top

    return width, height, left, top


def get_window_monitor(window):
    """
    根据窗口定义截图区域

    :param window: 窗口
    :return: monitor = {"top": window_y_main, "left": window_x_main, "width": width_main, "height": height_main}
    """
    # 定义截图区域
    res = get_window_size(window._hWnd)
    width_main, height_main, window_x_main, window_y_main = res
    monitor = {"left": window_x_main, "top": window_y_main, "width": width_main, "height": height_main}
    return monitor


def find_btn_location_once(monitor, img_path):
    """
    截图

    :param monitor: {"left": x, "top": y, "width": width, "height": height}
    :param img_path: 图片路径。根据实际情况使用
    :return: [x, y]
    """
    return do_screenshot(monitor, img_path)


def find_btn_location_window(window, img_path):
    # 定义截图区域
    monitor = get_window_monitor(window)
    return find_btn_location_once(monitor, img_path)


def do_screenshot(monitor, img_path):
    """
    定义截图区域（实时截图）

    :param monitor: {"top": y, "left": x, "width": width, "height": height}
    :param img_path: 图片路径。根据实际情况使用
    :return: [x, y]
    """
    with mss.mss() as sct:
        # 获取区域截屏，也就是大图
        region = sct.grab(monitor)
        # 更快
        big_pic = np.array(region)
        big_pic_hui_du = cv2.cvtColor(big_pic, cv2.COLOR_BGR2GRAY)
        # 获取小图片
        #small_pic = cv2.imread(img_path)
        # 获取小图片(支持中文文件名)
        small_pic = imread_chinese(img_path)
        # 灰度图片
        small_pic_hui_du = cv2.cvtColor(small_pic, cv2.COLOR_BGR2GRAY)
        # 在大图中，找小图片
        result = cv2.matchTemplate(big_pic_hui_du, small_pic_hui_du, cv2.TM_CCOEFF_NORMED)
        # 筛选结果(用np筛选以下结果高于0.85的)
        result_filter = np.where(result >= 0.8)
        # 将结果再次
        result_filter_list = list(zip(*result_filter[::-1]))
        if len(result_filter_list) > 0:
            return result_filter_list[0]
        else:
            return []


def imread_chinese(path):
    """
    支持识别中文名称的文件名

    :param path:
    :return:
    """
    stream = open(path, "rb")
    bytes_data = bytearray(stream.read())
    numpy_array = np.asarray(bytes_data, dtype=np.uint8)
    img = cv2.imdecode(numpy_array, -1)
    stream.close()
    return img


def get_windows_with_exact_title(title, single=False):
    """
    精确获取指定窗口

    # 使用示例
    exact_windows = get_windows_with_exact_title("Notepad")
    :param title:
    :param single: true返回对象，false返回数组
    :return:
    """
    windows = gw.getWindowsWithTitle(title)
    _windows = [w for w in windows if w.title == title]
    if len(_windows) == 0:
        return []
    if single:
        return _windows[0]
    return  _windows

def get_game_window(account):
    values = get_game_windows(account_list=[account])
    return values[0] if len(values) > 0 else None

def get_game_windows(account_list=None):
    """
    根据窗口标题，获取窗口（不要携带前缀xqApp）

    :param account_list: ["zhanghao1", "zhanghao2"]
    :return:
    """
    # 定义存放的主要窗口
    if account_list is None:
        return gw.getWindowsWithTitle("xqApp")
    game_window = []
    # 找窗口
    for account in account_list:
        # 去掉可能存在的 xqApp 前缀
        cleaned_account = account.replace("xqApp ", "").strip()
        results = get_windows_with_exact_title("xqApp " + cleaned_account)
        if len(results) > 0:
            game_window.append(results[0])
    return game_window

def do_screenshot_batch_by_window(window, img_paths):
    monitor = get_window_monitor(window)
    file_path, result = do_screenshot_batch_by_monitor(monitor, img_paths)
    return result

def do_screenshot_batch_by_monitor(monitor, img_paths, threshold=0.8):
    """
    定义截图区域（实时截图），支持多张图片识别
    :param monitor: {"left": x, "top": y, "width": width, "height": height}
    :param img_paths: 图片路径列表，例如 ["img1.png", "img2.png"]
    :param threshold: 匹配阈值
    :return: 第一个识别到的图片路径和坐标，格式为 (img_path, [x, y])，如果都没识别到则返回 (None, None)
    """
    # monitor:
    with mss.mss() as sct:
        # 获取区域截屏，也就是大图
        region = sct.grab(monitor)
        big_pic = np.array(region)
        big_pic_gray = cv2.cvtColor(big_pic, cv2.COLOR_BGR2GRAY)

        for img_path in img_paths:
            print(f"正在加载图片：{img_path}")
            # 读取小图并转为灰度图（支持中文文件名）
            small_pic = imread_chinese(img_path)
            if small_pic is None:
                print(f"无法加载图片：{img_path}")
                continue
            small_pic_gray = cv2.cvtColor(small_pic, cv2.COLOR_BGR2GRAY)
            # 模板匹配
            result = cv2.matchTemplate(big_pic_gray, small_pic_gray, cv2.TM_CCOEFF_NORMED)
            loc = np.where(result >= threshold)

            # 提取第一个匹配点
            matches = list(zip(*loc[::-1]))
            if matches:
                return img_path, matches[0]  # 立即返回第一个识别到的图片路径和坐标

        return None, None  # 未找到任何匹配项

def do_screenshot_vip(window, img_path, scale_range=(0.70, 0.78), step=0.1, im_show=False):
    """
    定义截图区域（实时截图），并使用多尺度模板匹配查找目标图像。
    使用场景：
        屏幕分辨率相同（如 1920x1080）；
        程序窗口大小不同（比如一个游戏窗口是 800x600，另一个是 1280x720）；
        你在某个窗口中截图了一个按钮或图标（如 button.png），想在其他窗口尺寸下也识别到这个按钮；

    :param window: 窗口
    :param img_path: 图片路径（支持中文）
    :param scale_range: 模板缩放范围 (min_scale, max_scale)
    :param step: 缩放步长
    :param im_show: 是否显示调试图像
    :return: [x, y] 或空列表 []
    """
    # 获取截图预取 monitor: {"left": x, "top": y, "width": width, "height": height}
    monitor = get_window_monitor(window)
    with mss.mss() as sct:
        # 截图
        region = sct.grab(monitor)
        big_pic = np.array(region)
        big_pic_gray = cv2.cvtColor(big_pic, cv2.COLOR_BGRA2GRAY)

        if im_show:
            cv2.imshow("大图", big_pic_gray)
            cv2.waitKey(0)

        # 加载模板图片（支持中文路径）
        small_pic = imread_chinese(img_path)
        small_pic_gray = cv2.cvtColor(small_pic, cv2.COLOR_BGR2GRAY)

        found = None

        # 获取模板的原始尺寸
        th, tw = small_pic_gray.shape

        # 尝试多个缩放比例
        for scale in np.arange(scale_range[0], scale_range[1], step):
            # 调整模板大小
            resized = cv2.resize(small_pic_gray, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
            rh, rw = resized.shape

            # 如果调整后的模板比截图还大，则跳过
            if rh > big_pic_gray.shape[0] or rw > big_pic_gray.shape[1]:
                continue

            # 模板匹配
            result = cv2.matchTemplate(big_pic_gray, resized, cv2.TM_CCOEFF_NORMED)
            _, max_val, _, max_loc = cv2.minMaxLoc(result)

            # 设置匹配阈值
            if max_val >= 0.8:
                print(f"找到匹配项，缩放比例: {scale:.2f}，相似度: {max_val:.2f}")
                center_x = max_loc[0] + int(rw / 2)
                center_y = max_loc[1] + int(rh / 2)
                found = (center_x, center_y)
                break  # 找到后立即退出循环

        if found:
            return list(found)
        else:
            return []



def find_with_retry(window, img_path, max_retries=15, retry_interval=1, down_presses=3, down_interval=0.2):
    """
    尝试查找按钮位置，最多重试 max_retries 次

    :param window: 窗口对象
    :param img_path: 图片路径
    :param max_retries: 最大重试次数，默认 15
    :param retry_interval: 每次重试之间的间隔时间（秒），默认 1 秒
    :param down_presses: 每次键盘按下的次数，默认 3 次
    :param down_interval: 按键之间的间隔时间，默认 0.2 秒
    :return: 如果找到，返回位置坐标；否则返回 None
    """
    for _ in range(max_retries):
        location = find_btn_location_window(window, img_path)
        if location is not None:
            return location
        pyautogui.press('down', presses=down_presses, interval=down_interval)
        time.sleep(retry_interval)
    return None

def capture_and_save_screenshot_by_window(save_directory, file_name="screenshot.png", window=None):
    """
    根据窗口截图后，保存至指定目录
    :param save_directory:
    :param save_directory: str，截图保存的目录路径。
    :param file_name: str，保存的文件名，默认为 'screenshot.png'。
    :param window 窗口
    """
    monitor = get_window_monitor(window)
    capture_and_save_screenshot(save_directory, file_name, monitor)

def capture_and_save_screenshot(save_directory, file_name="screenshot.png", monitor=None):
    """
    截图并保存到指定目录，支持全屏或指定区域截图。
    使用示例
    monitor_info = {"top": 100, "left": 200, "width": 800, "height": 600}
    capture_and_save_screenshot("/path/to/your/directory", "window_screenshot.png", monitor=monitor_info)

    :param save_directory: str，截图保存的目录路径。
    :param file_name: str，保存的文件名，默认为 'screenshot.png'。
    :param monitor: dict，指定截图区域，格式为 {"top": x, "left": y, "width": w, "height": h}。
                    如果为 None，则默认截取主显示器全屏。
    """
    # 如果目录不存在，则创建
    if not os.path.exists(save_directory):
        os.makedirs(save_directory)

    # 截图
    with mss.mss() as sct:
        if monitor is None:
            monitor = sct.monitors[1]  # 默认截取主显示器
        else:
            # 将用户传入的窗口参数转换为 mss 所需格式
            monitor = {
                "top": monitor["top"],
                "left": monitor["left"],
                "width": monitor["width"],
                "height": monitor["height"]
            }

        screenshot = sct.grab(monitor)

    # 将截图保存为图片文件
    img = Image.frombytes("RGB", screenshot.size, screenshot.rgb)
    img.save(os.path.join(save_directory, file_name))